using System;
using CodePlex.TfsLibrary.ObjectModel;
using CodePlex.TfsLibrary.RepositoryWebSvc;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class TfsEngineResolveTest
    {
        public class Resolve
        {
            [Fact]
            public void NullLocalPathThrows()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Resolve(null, true, null);
                                                     });
            }

            [Fact]
            public void PathNotFound()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();

                engine.Resolve(@"C:\Foo", true, delegate(SourceItem item,
                                                         SourceItemResult result)
                                                {
                                                    callbackItem = item;
                                                    callbackResult = result;
                                                });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_PathNotFound, callbackResult);
            }
        }

        public class Resolve_File
        {
            [Fact]
            public void AddedFile()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Add);

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate
                                                        {
                                                            throw new InvalidOperationException("Should not be called back");
                                                        });

                // Nothing to assert... should be a NOOP
            }

            [Fact]
            public void ConflictedFile()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt.r3", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt.r5", "other text");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt.mine", "some text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\bar.txt", @"C:\Foo\bar.txt.r5", 5);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "Manual merge");

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate(SourceItem item,
                                                                 SourceItemResult result)
                                                        {
                                                            callbackItem = item;
                                                            callbackResult = result;
                                                        });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(5, callbackItem.LocalChangesetId);
                Assert.Equal(Constants.NullChangesetId, callbackItem.LocalConflictChangesetId);
                Assert.Equal("Manual merge", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.Equal("other text", engine.FileSystem.ReadAllText(@"C:\Foo\_tfs\text-base\bar.txt.tfs-base"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r3"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r5"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.mine"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void DeletedFile()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Delete);

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate
                                                        {
                                                            throw new InvalidOperationException("Should not be called back");
                                                        });

                // Nothing to assert... should be a NOOP
            }

            [Fact]
            public void MissingFile()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteFile(@"C:\Foo\bar.txt");

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate
                                                        {
                                                            throw new InvalidOperationException("Should not be called back");
                                                        });

                // Nothing to assert... should be a NOOP
            }

            [Fact]
            public void ModifiedFile()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "other text");

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate
                                                        {
                                                            throw new InvalidOperationException("Should not be called back");
                                                        });

                // Nothing to assert... should be a NOOP
            }

            [Fact]
            public void NotInAWorkingFolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate(SourceItem item,
                                                                 SourceItemResult result)
                                                        {
                                                            callbackItem = item;
                                                            callbackResult = result;
                                                        });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_NotInAWorkingFolder, callbackResult);
            }

            [Fact]
            public void UnmodifiedFile()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 3, SourceItemStatus.Unmodified);

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate
                                                        {
                                                            throw new InvalidOperationException("Should not be called back");
                                                        });

                // Nothing to assert... should be a NOOP
            }

            [Fact]
            public void UnversionedFile()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);

                engine.Resolve(@"C:\Foo\bar.txt", true, delegate(SourceItem item,
                                                                 SourceItemResult result)
                                                        {
                                                            callbackItem = item;
                                                            callbackResult = result;
                                                        });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.E_NotUnderSourceControl, callbackResult);
            }
        }

        public class Resolve_Folder
        {
            [Fact]
            public void FolderNotUnderSourceControl()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);

                engine.Resolve(@"C:\Foo\Bar", false, delegate(SourceItem item,
                                                              SourceItemResult result)
                                                     {
                                                         callbackItem = item;
                                                         callbackResult = result;
                                                     });

                Assert.Equal(@"C:\Foo\Bar", callbackItem.LocalName);
                Assert.Equal(ItemType.Folder, callbackItem.ItemType);
                Assert.Equal(SourceItemResult.E_NotUnderSourceControl, callbackResult);
            }

            [Fact]
            public void MissingFolder()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 2, 2, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteDirectory(@"C:\Foo\Bar", true);

                engine.Resolve(@"C:\Foo", true, delegate
                                                {
                                                    throw new InvalidOperationException("Should not be called back");
                                                });
            }

            [Fact]
            public void NonRecursiveNoFilesToResolve()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\unmodified.txt", "Hello there");
                engine.FileSystem.WriteAllText(@"C:\Foo\unversioned.txt", "unversioned");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\unmodified.txt", 1, 2, SourceItemStatus.Unmodified);

                engine.Resolve(@"C:\Foo", false, delegate
                                                 {
                                                     throw new InvalidOperationException("Should not be called back");
                                                 });
            }

            [Fact]
            public void NonRecursiveWithConflictedFilesInSubFolders()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unmodified.txt", "Hello there");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unversioned.txt", "unversioned");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unmodified.txt.r5", "R5");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\unmodified.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\Bar\unmodified.txt", @"C:\Foo\Bar\unmodified.txt.r5", 5);

                engine.Resolve(@"C:\Foo", false, delegate
                                                 {
                                                     throw new InvalidOperationException("Should not get here!");
                                                 });
            }

            [Fact]
            public void NonRecursiveWithFilesToResolve()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\unmodified.txt", "Hello there");
                engine.FileSystem.WriteAllText(@"C:\Foo\unversioned.txt", "unversioned");
                engine.FileSystem.WriteAllText(@"C:\Foo\unmodified.txt.r5", "R5");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\unmodified.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\unmodified.txt", @"C:\Foo\unmodified.txt.r5", 5);

                engine.Resolve(@"C:\Foo", false, delegate(SourceItem item,
                                                          SourceItemResult result)
                                                 {
                                                     callbackItem = item;
                                                     callbackResult = result;
                                                 });

                Assert.NotNull(callbackItem);
                Assert.Equal(@"C:\Foo\unmodified.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Recursive()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unmodified.txt", "Hello there");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unversioned.txt", "unversioned");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unmodified.txt.r5", "R5");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\unmodified.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\Bar\unmodified.txt", @"C:\Foo\Bar\unmodified.txt.r5", 5);

                engine.Resolve(@"C:\Foo", true, delegate(SourceItem item,
                                                         SourceItemResult result)
                                                {
                                                    callbackItem = item;
                                                    callbackResult = result;
                                                });

                Assert.NotNull(callbackItem);
                Assert.Equal(@"C:\Foo\Bar\unmodified.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void RecursiveWontGoIntoUntrackedFolder()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);

                engine.Resolve(@"C:\Foo", true, delegate
                                                {
                                                    throw new InvalidOperationException("Should not get here");
                                                });
            }
        }
    }
}